package ua.yandex.shad.tempseries;
//import java.math.*;

class IllegalTemperatureValueException extends Exception {
    /*Исключение означает температуру меньше -273*/
}

class IllegalDeviationValueException extends Exception {
    /*Исключение обозначает, что дисперсия превышает Максимальное значение double.*/
}

public class TemperatureSeriesAnalysis {
    
    private final double[] temperatureSeries;

    public TemperatureSeriesAnalysis(double[] temperatureSeries) throws IllegalTemperatureValueException {
        this.temperatureSeries = temperatureSeries;
        for(double x : temperatureSeries){
            if (x < -273){
                throw new IllegalTemperatureValueException();
            }
        }
    }
    
    public double calcAverageTemp(){
        double average = 0;
        for(double x : temperatureSeries){
            average += x / temperatureSeries.length;
        }
        return average;
    }
    
    public double calcTempDeviation() throws IllegalDeviationValueException{
        double variance = 0;
        double average = calcAverageTemp();
        for(double x : temperatureSeries){
            if ((x - average) / Math.sqrt((double)temperatureSeries.length) > Math.sqrt(Double.MAX_VALUE)
                    || ((x-average) / temperatureSeries.length * (x - average) > Double.MAX_VALUE - variance)){
                throw new IllegalDeviationValueException();
            }
            variance += (x - average) / temperatureSeries.length * (x - average);
        }
        return variance;
    }
    
    public double findTempClosestToZero(){
        if (temperatureSeries.length == 0){
            return 0;
        }
        double closest = temperatureSeries[0];
        for(double x : temperatureSeries){
            if (-x == closest){
                closest = Math.abs(x);
            }
            else if (Math.abs(x) <= Math.abs(closest)){
                closest = x;
            }
        }
        return closest;
    }
    
    public double findTempClosestToValue(double tempValue){
        if (temperatureSeries.length == 0){
            return 0;
        }
        double closest = temperatureSeries[0];
        for(double x : temperatureSeries){
            /*Такая странная реализация выбрана из-за особенностей арифметики типа double*/
            if (x < closest){
                if (tempValue <= x){
                    closest = x;
                }
                else if (tempValue <= closest){
                    closest = (closest / 2 + x / 2) <= tempValue ? closest : x;
                }
            }
            else if (closest <= x){
                if (tempValue >= x){
                    closest = x;
                }
                else if (tempValue >= closest){
                    closest = (closest / 2 + x / 2) <= tempValue ? x : closest;
                }
            }
        }
        return closest;
    }
    
    public double[] findTempsLessThen(double tempValue){
        double[] tempLess = new double[temperatureSeries.length];
        int i = 0;
        for(double x : temperatureSeries){
            if (x < tempValue){
                tempLess[i++] = x;                
            }
        }
        if (i == 0){
            double[] less = {0};
            return less;
        }
        double[] less;
        less = new double[i];
        System.arraycopy(tempLess, 0, less, 0, i);
        return less;
    }
    public double[] findTempsGreaterThen(double tempValue){        
        double[] tempGreater= new double[temperatureSeries.length];
        int i = 0;
        for(double x : temperatureSeries){
            if (x >= tempValue){
                tempGreater[i++] = x;                
            }
        }
        if (i == 0){
            double[] greater = {0};
            return greater;
        }
        double[] greater;
        greater=new double[i];
        System.arraycopy(tempGreater, 0, greater, 0, i);
        return greater;
    }
    
    double[] forecatsTemp(){
        return temperatureSeries;
    }
}
